package com.example.zyl.common.config;

import cn.hutool.core.annotation.AnnotationUtil;
import com.example.zyl.common.exception.ServiceException;
import com.example.zyl.common.query.annotation.ApiAliasField;
import com.example.zyl.common.utils.ConditionUtils;
import com.example.zyl.common.utils.ToolUtils;
import com.example.zyl.common.utils.constant.Constant;
import com.mysql.cj.jdbc.result.ResultSetImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;


@Component
@Slf4j
@RequiredArgsConstructor
public class DataSourceConfig {

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.dbType}")
    private Class<?> dbType;


    /**
     * 动态数据源配置
     *
     * @return DynamicDataSource
     */
    @Bean
    public DynamicDataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 默认数据源
        DataSource defaultDataSource = DataSourceBuilder.create()
                .url(url)
                .username(username)
                .password(password)
                .driverClassName(driverClassName)
                .build();

        Map<Object, Object> targetDataSources = this.loadDataSourceProperties();
        log.info("load datasource success");
        // 设置多个数据源
        dynamicDataSource.setTargetDataSources(targetDataSources);
        // 设置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
        return dynamicDataSource;
    }


    /**
     * 加载数据源配置
     *
     * @return Map<Object, Object>
     */
    public Map<Object, Object> loadDataSourceProperties() {
        // 加载所有数据源配置
        Map<Object, Object> targetDataSources = new HashMap<>();

        // 连接数据库
        try (Connection connection = DriverManager.getConnection(url, username, password)) {

            // 判断是否有@Alias注解
            boolean hasAlias = AnnotationUtil.hasAnnotation(dbType, ApiAliasField.class);

            ConditionUtils.throwException(hasAlias).accept("dbType must have @Alias annotation");
            // 获取数据库配置sql
            String byClassSql = ToolUtils.getByClassSql(dbType);

            // 创建PreparedStatement对象
            PreparedStatement preparedStatement = connection.prepareStatement(byClassSql);
            // 执行查询
            ResultSet resultSet = preparedStatement.executeQuery();

            // 循环处理结果集
            while (resultSet.next()) {
                this.handleFieldValue(resultSet, targetDataSources);
            }

        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }

        return targetDataSources;
    }

    /**
     * 处理字段值
     *
     * @param resultSet         ResultSet
     * @param targetDataSources Map
     */
    public void handleFieldValue(ResultSet resultSet, Map<Object, Object> targetDataSources)
            throws Exception {

        // 获取结果集的列字段
        com.mysql.cj.result.Field[] fields = ((ResultSetImpl) resultSet).getColumnDefinition().getFields();
        // 创建数据源配置对象
        DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
        // 获取Class对象
        Class<?> dataSourceClass = dataSourceBuilder.getClass();
        // 特殊字段
        Stream.Builder<String> builder = Stream.builder();
        // 循环处理列字段
        for (com.mysql.cj.result.Field field : fields) {
            // 获取列名
            String columnLabel = field.getColumnLabel();
            // 获取列值
            Object value = resultSet.getObject(columnLabel);
            // 获取对象的字段
            Field declaredField = dbType.getDeclaredField(columnLabel);
            // 判断是否有@Alias注解
            ApiAliasField annotation = declaredField.getAnnotation(ApiAliasField.class);
            if (null != annotation) {
                // 判断是否是特殊别名
                boolean alias = annotation.isAlias();
                // 获取别名值
                String name = annotation.value();
                if (alias) {
                    builder.add(name);
                    if (ToolUtils.isEmpty(name)) {
                        builder.add(columnLabel);
                    }
                    continue;
                }
                if (ToolUtils.isEmpty(name)) {
                    name = columnLabel;
                }
                // 设置别名值
                Method method = dataSourceClass.getMethod(name, String.class);
                method.invoke(dataSourceBuilder, value.toString());
            }
        }
        DataSource build = dataSourceBuilder.build();
        String mapKey = builder.build().findFirst().orElse(Constant.DB_NAME);
        targetDataSources.put(resultSet.getString(mapKey), build);
    }
}
